#include "app_buffer.h"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include "thirdparty/log.h"



static pthread_mutex_t lock_initializer = PTHREAD_MUTEX_INITIALIZER;
int app_buffer_init(Buffer* buffer, int size)
{
    buffer->ptr = malloc(size);
    if(!buffer->ptr)
    {
        log_warn("Not enough memory for buffer: %p", buffer);
        return  -1;
    }
    buffer->start = 0;
    buffer->size = size;
    buffer->len = 0;
    memcpy(&buffer->lock, &lock_initializer, sizeof(pthread_mutex_t));
    log_debug("Buffer:%p created!", buffer);
    return 0;
}

int app_buffer_read(Buffer* buffer, void* buf, int len)
{
    if (!buffer || !buf) {
        log_warn("Buffer or buf not valid");
        return -1;
    }
    // 首先要确定读取的数据有多长
    pthread_mutex_lock(&buffer->lock);
    if (len > buffer->len) {
        len = buffer->len;
    }

    if (len == 0) {
        pthread_mutex_unlock(&buffer->lock);
        return 0;
    }

    // 再次判断是否能过一次读取
    if (buffer->start + len <= buffer->size) {
        // 读一次
        memcpy(buf, buffer->ptr + buffer->start, len);
        buffer->start += len;
    } else {
        // 读两次
        int first_len = buffer->size - buffer->start;
        memcpy(buf, buffer->ptr + buffer->start,   first_len);
        memcpy(buf + first_len, buffer->ptr, len - first_len);
        buffer->start = len - first_len;
    }

    buffer->len -= len;
    pthread_mutex_unlock(&buffer->lock);
    log_trace("Buffer status after read: start: %d, size: %d", buffer->start, buffer->len);
    return len;
}

int app_buffer_write(Buffer* buffer, void* buf, int len)
{
    if (!buffer || !buf) {
        log_warn("Buffer or buffer not valid");
        return -1;
    }
    pthread_mutex_lock(&buffer->lock);
    if (len > buffer->size - buffer->len) {
        // 剩余空间无法写入
        log_warn("Buffer %p is not enough", buffer);
        pthread_mutex_unlock(&buffer->lock);
        return -1;
    }

    // 数据分一次写还是， 两次写
    int write_offset = buffer->start + buffer->len;
    if (write_offset > buffer->size) {
        write_offset -= buffer->size;
    }
    // 判断写入起点到尾部还有多少空间
    if (write_offset + len <= buffer->size) {
        // 一次就能写入
        memcpy(buffer->ptr + write_offset, buf, len);
    } else {
        // 需要写入两次
        int first_len = buffer->size - write_offset;
        memcpy(buffer->ptr + write_offset, buf,  first_len);
        memcpy(buffer->ptr, buf + first_len, len - first_len);
    }

    buffer->len += len;
    pthread_mutex_unlock(&buffer->lock);
    log_trace("Buffer status after write: start: %d, size: %d", buffer->start, buffer->len);
    return 0;
}

void app_buffer_close(Buffer* buffer)
{
    if(buffer->ptr)
    {
        free(buffer->ptr);
        buffer->ptr = NULL;
    }
    buffer->size = 0;
    buffer->len = 0;
    buffer->start = 0;
}